﻿#pragma once

#include <DirectXMath.h>
#include "Vec4.h"
#include "Vec3.h"
#include "Quaternion.h"

namespace Base {

	using namespace DirectX;

	// Matrix4x4
		// 行优先
		// 左手坐标系
	struct Matrix4x4
	{
		union
		{
			struct
			{
				Vec4 row0;
				Vec4 row1;
				Vec4 row2;
				Vec4 row3;
			};
			XMFLOAT4X4 data;
			float arr[4][4];
		};

		Matrix4x4() {};
		Matrix4x4(const Vec4& pRow0, const Vec4& pRow1, const Vec4& pRow2, const Vec4& pRow3) {
			row0 = pRow0;
			row1 = pRow1;
			row2 = pRow2;
			row3 = pRow3;
		}



		Matrix4x4& SetIdentity() {
			XMStoreFloat4x4(&data, XMMatrixIdentity());
			return *this;
		}

		Matrix4x4 operator*(const Matrix4x4& rhs) const {
			Matrix4x4 result;
			XMStoreFloat4x4(&result.data, XMMatrixMultiply(XMLoadFloat4x4(&data), XMLoadFloat4x4(&rhs.data)));
			return result;
		}

		float operator()(int rowIndex, int columnIndex)const {
			return arr[rowIndex][columnIndex];
		}

		float& operator()(int rowIndex, int columnIndex) {
			return arr[rowIndex][columnIndex];
		}

		// 转置
		Matrix4x4 Transpose() const {
			Matrix4x4 result;
			XMStoreFloat4x4(&result.data, XMMatrixTranspose(XMLoadFloat4x4(&data)));
			return result;
		}

		Matrix4x4& TransposeSelf() {
			XMStoreFloat4x4(&data, XMMatrixTranspose(XMLoadFloat4x4(&data)));
			return *this;
		}

		// 求逆
		Matrix4x4 Inverse() const {
			Matrix4x4 result;
			XMStoreFloat4x4(&result.data, XMMatrixInverse(nullptr, XMLoadFloat4x4(&data)));
			return result;
		}

		Matrix4x4& InverseSelf() {
			XMStoreFloat4x4(&data, XMMatrixInverse(nullptr, XMLoadFloat4x4(&data)));
			return *this;
		}

		// 是否是单位矩阵
		bool IsIdentity() {
			return XMMatrixIsIdentity(XMLoadFloat4x4(&data));
		}

		// 求矩阵行列式的值
		float Determinant() const {
			return XMVectorGetX(XMMatrixDeterminant(XMLoadFloat4x4(&data)));
		}

		// 将矩阵的缩放、旋转、平移分量拆出来，其中旋转分量是四元数
		bool Decompose(Vec3& t, Quaternion& r, Vec3& s) const;

		// 
		// static
		static Matrix4x4 TRS(const Vec3&  t, const Quaternion& r, const Vec3& s);

		static Matrix4x4 CreateTranslation(float x, float y, float z);
		static Matrix4x4 CreateTranslation(const Vec3& v);

		static Matrix4x4 CreateScale(float sx, float sy, float sz);
		static Matrix4x4 CreateScale(const Vec3& v);

		// 绕X轴旋转(弧度，从X轴正方向朝原点看顺时针)矩阵
		static Matrix4x4 CreateRotationX(float rad);

		static Matrix4x4 CreateRotationY(float rad);

		static Matrix4x4 CreateRotationZ(float rad);

		/*
			按照先绕Z轴，然后X轴，最后Y轴的顺序得到旋转矩阵(弧度)
			结果与下面的矩阵 m 相同
			Matrix4x4 r1 = Matrix4x4::CreateRotationZ(roll);
			Matrix4x4 r2 = Matrix4x4::CreateRotationX(pitch);
			Matrix4x4 r3 = Matrix4x4::CreateRotationY(yaw);
			Matrix4x4 m = r1 * r2 * r3;
		 */
		static Matrix4x4 CreateRollPitchYaw(float pitch, float yaw, float roll);

		// 按照 Z-X-Y 顺序,创造一个旋转矩阵
		static Matrix4x4 CreateRotation(float x, float y, float z);

		// 返回  (lhs * rhs).Transpose();
		static Matrix4x4 MatrixMultiplyTranspose(const Matrix4x4& lhs, const Matrix4x4& rhs);


		// 由轴-角得到旋转矩阵  
		static Matrix4x4 CreateRotationFromAxisAngle(const Vec3& normalizeAxis, float rad);

		static Matrix4x4 CreatePerspectiveFovLH(float rad, float aspect, float near, float far);

		static Matrix4x4 CreateLookAtLH(const Vec3& pos, const Vec3& target, const Vec3& up);

		// TODO: 等待实现
		// 1. XMMatrixReflect
		// 2. XMMatrixShadow
		// 5. XMVector3Project  
		// 6. XMVector3Unproject


	};
}
